//package org.msz.keycloak;
//
//import org.dcm4che3.net.Device;
//import org.dcm4che3.net.KeycloakClient;
//import org.dcm4che3.net.WebApplication;
//import org.jboss.resteasy.client.jaxrs.ResteasyClient;
//import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
//import org.keycloak.TokenVerifier;
//import org.keycloak.admin.client.Keycloak;
//import org.keycloak.admin.client.KeycloakBuilder;
//import org.keycloak.admin.client.token.TokenManager;
//import org.keycloak.common.util.KeycloakUriBuilder;
//import org.keycloak.constants.ServiceUrlConstants;
//import org.keycloak.jose.jwk.JSONWebKeySet;
//import org.keycloak.jose.jwk.JWK;
//import org.keycloak.jose.jws.JWSInput;
//import org.keycloak.representations.AccessToken;
//import org.keycloak.representations.AccessTokenResponse;
//import org.keycloak.util.JWKSUtils;
//import org.keycloak.util.JsonSerialization;
//import org.msz.dcm.event.ArchiveServiceEvent;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.context.event.EventListener;
//import org.springframework.stereotype.Component;
//import org.springframework.web.context.annotation.ApplicationScope;
//
//import javax.ws.rs.client.Invocation;
//import javax.ws.rs.client.WebTarget;
//import java.io.InputStream;
//import java.security.PublicKey;
//import java.util.Map;
//import java.util.concurrent.ExecutorService;
//import java.util.concurrent.ScheduledExecutorService;
//
//@Component
//@ApplicationScope
//public class AccessTokenRequestor {
//    @Autowired
//    private Device device;
//
//    @Autowired
//    private ExecutorService executorService;
//
//    @Autowired
//    private ScheduledExecutorService scheduledExecutor;
//
//    private volatile CachedKeycloak cachedKeycloakClient;
//    private volatile CachedPublicKey cachedPublicKey;
//
//    @EventListener
//    public void onArchiveServiceEvent(ArchiveServiceEvent event) {
//        if (event.getType() == ArchiveServiceEvent.Type.RELOADED) {
//            cachedKeycloakClient = null;
//            cachedPublicKey = null;
//        }
//    }
//
//    public AccessTokenWithExpiration getAccessToken2(WebApplication webApp) throws Exception {
//        CachedKeycloak tmp = toCachedKeycloakClient(webApp);
//        TokenManager tokenManager = tmp.keycloak.tokenManager();
//        AccessTokenResponse accessToken = tokenManager.getAccessToken();
//        return new AccessTokenWithExpiration(
//                accessToken.getToken(),
//                accessToken.getExpiresIn());
//    }
//
//    public AccessTokenWithExpiration getAccessToken2(KeycloakClient keycloakClient) throws Exception {
//        CachedKeycloak tmp = toCachedKeycloakClient(keycloakClient);
//        TokenManager tokenManager = tmp.keycloak.tokenManager();
//        AccessTokenResponse accessToken = tokenManager.getAccessToken();
//        return new AccessTokenWithExpiration(
//                accessToken.getToken(),
//                accessToken.getExpiresIn());
//    }
//
//    private CachedKeycloak toCachedKeycloakClient(WebApplication webApp) throws Exception {
//        CachedKeycloak tmp = cachedKeycloakClient;
//        if (tmp == null || !tmp.keycloakID.equals(webApp.getKeycloakClientID())) {
//            KeycloakClient keycloakClient = webApp.getKeycloakClient();
//            if (keycloakClient == null)
//                throw new IllegalArgumentException("No Keycloak Client configured with ID:" + webApp.getKeycloakClientID());
//
//            cachedKeycloakClient = tmp = new CachedKeycloak(
//                    keycloakClient.getKeycloakClientID(), toKeycloak(keycloakClient));
//        }
//        return tmp;
//    }
//
//    private CachedKeycloak toCachedKeycloakClient(KeycloakClient kc) throws Exception {
//        CachedKeycloak tmp = cachedKeycloakClient;
//        if (tmp == null || !tmp.keycloakID.equals(kc.getKeycloakClientID()))
//            cachedKeycloakClient = tmp = new CachedKeycloak(kc.getKeycloakClientID(), toKeycloak(kc));
//
//        return tmp;
//    }
//
//    public ResteasyClientBuilder resteasyClientBuilder(
//            String url, boolean allowAnyHostname, boolean disableTrustManager) throws Exception {
//        ResteasyClientBuilder builder = new ResteasyClientBuilder();
//        if (url.toLowerCase().startsWith("https")) {
//            builder.sslContext(device.sslContext())
//                    .hostnameVerification(allowAnyHostname
//                            ? ResteasyClientBuilder.HostnameVerificationPolicy.ANY
//                            : ResteasyClientBuilder.HostnameVerificationPolicy.WILDCARD);
//            if (disableTrustManager)
//                builder.disableTrustManager();
//        }
//        builder.executorService(executorService);
//        builder.scheduledExecutorService(scheduledExecutor);
//        return builder;
//    }
//
//    public boolean verifyUsernamePasscode(KeycloakClient kc, String role) throws Exception {
//        try (Keycloak keycloak = toKeycloak(kc)) {
//            TokenManager tokenManager = keycloak.tokenManager();
//            JWSInput jws = new JWSInput(tokenManager.getAccessToken().getToken());
//            AccessToken token = jws.readJsonContent(AccessToken.class);
//            return role == null || token.getRealmAccess().isUserInRole(role);
//        }
//    }
//
//    private Keycloak toKeycloak(KeycloakClient kc) throws Exception {
//        return KeycloakBuilder.builder()
//                .serverUrl(kc.getKeycloakServerURL())
//                .realm(kc.getKeycloakRealm())
//                .clientId(kc.getKeycloakClientID())
//                .clientSecret(kc.getKeycloakClientSecret())
//                .username(kc.getUserID())
//                .password(kc.getPassword())
//                .grantType(kc.getKeycloakGrantType().name())
//                .resteasyClient(resteasyClientBuilder(
//                        kc.getKeycloakServerURL(), kc.isTLSAllowAnyHostname(), kc.isTLSDisableTrustManager()).build())
//                .build();
//    }
//
//
//    public boolean verifyJWT(String tokenString, KeycloakClient kc, String role) throws Exception {
//        String serverURL = kc.getKeycloakServerURL();
//        String realmName = kc.getKeycloakRealm();
//        KeycloakUriBuilder authUrlBuilder = KeycloakUriBuilder.fromUri(serverURL);
//        String jwksUrl = authUrlBuilder.clone()
//                .path(ServiceUrlConstants.JWKS_URL).build(realmName).toString();
//        String realmUrl = authUrlBuilder.clone()
//                .path(ServiceUrlConstants.REALM_INFO_PATH).build(realmName).toString();
//        TokenVerifier<AccessToken> tokenVerifier = TokenVerifier.create(tokenString, AccessToken.class);
//        tokenVerifier.withDefaultChecks().realmUrl(realmUrl);
//        String kid = tokenVerifier.getHeader().getKeyId();
//        PublicKey publicKey = getPublicKey(kid, jwksUrl, kc);
//        tokenVerifier.publicKey(publicKey);
//        tokenVerifier.verify();
//        return role == null || tokenVerifier.getToken().getRealmAccess().isUserInRole(role);
//    }
//
//    private PublicKey getPublicKey(String kid, String jwksUrl, KeycloakClient kc)
//            throws Exception {
//        CachedPublicKey tmp = cachedPublicKey;
//        if (tmp != null
//                && tmp.jwksUrl.equals(jwksUrl)
//                && tmp.kid.equals(kid)) {
//            return tmp.key;
//        }
//        ResteasyClient client = resteasyClientBuilder(
//                kc.getKeycloakServerURL(),
//                kc.isTLSAllowAnyHostname(),
//                kc.isTLSDisableTrustManager())
//                .build();
//        try {
//            WebTarget target = client.target(jwksUrl);
//            Invocation.Builder request = target.request();
//            try (InputStream is = request.get(InputStream.class)) {
//                JSONWebKeySet jwks = JsonSerialization.readValue(is, JSONWebKeySet.class);
//                Map<String, PublicKey> publicKeys = JWKSUtils.getKeysForUse(jwks, JWK.Use.SIG);
//                PublicKey publicKey = publicKeys.get(kid);
//                if (publicKey != null) {
//                    cachedPublicKey = new CachedPublicKey(jwksUrl, kid, publicKey);
//                }
//                return publicKey;
//            }
//        } finally {
//            client.close();
//        }
//    }
//
//    private static class CachedKeycloak {
//        final String keycloakID;
//        final Keycloak keycloak;
//
//        CachedKeycloak(String keycloakID, Keycloak keycloak) {
//            this.keycloakID = keycloakID;
//            this.keycloak = keycloak;
//        }
//    }
//
//    public static class AccessTokenWithExpiration {
//        final String token;
//        final long expiration;
//
//        AccessTokenWithExpiration(String tokenStr, long expiresIn) {
//            token = tokenStr;
//            expiration = expiresIn;
//        }
//
//        public String getToken() {
//            return token;
//        }
//
//        public long getExpiration() {
//            return expiration;
//        }
//    }
//
//    private static class CachedPublicKey {
//        final String jwksUrl;
//        final String kid;
//        final PublicKey key;
//
//        private CachedPublicKey(String jwksUrl, String kid, PublicKey key) {
//            this.jwksUrl = jwksUrl;
//            this.kid = kid;
//            this.key = key;
//        }
//    }
//}
